﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using CIAWorldMap;
using MapSurface;
using OSMLib;
using WGS84;

namespace LaoMap
{

    /*
     * 
     * http://wiki.openstreetmap.org/wiki/WikiProject_Laos
     
     * How to acquire data... the steps....
     * Get CIA World map data - this is used in osmGetter to define the outline to clip the OSM tiles. Limit to national boundary
     * osmGetter takes several days to harvest the data from OSM.
     * 
     * LaoMap - click "Load OSM" to read the file structure. Data is visible! (Takes several minutes)
     * blacklist.txt record the files that don't conribute to the image - that is a tile contains the same ways as a previously loaded one.
     * 
     * Click "Create bin" to create a lightweight copy  (7 meg file)
     * 
     * restart - now click "load bin" (Takes a second)
     * 
     * 
     * 
     * */
    /* Useful set of hi res raster maps
     * http://www.flickr.com/photos/captain-bob/sets/72157626498904641/with/5677008454/
     */

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        OpenMapLibrary _openMapLibrary;
        readonly Dictionary<string, MapSegment> _segments2 = new Dictionary<string, MapSegment>();

        readonly Dictionary<string, Place> _places = new Dictionary<string, Place>();
        LaosBorder _laosBorder = new LaosBorder();

        Canvas _dlgCanvas;

        Canvas _dlgCanvasMap;
        readonly Surface _surface;
        readonly OsmRender _osmRenderer;
        readonly PlacesRender _placesRenderer;
        readonly CIARender _ciaRender;
        readonly RenderOpenMapLibrary _RenderOpenMapLibrary;

        public MainWindow()
        {
            InitializeComponent();
            _openMapLibrary = new OpenMapLibrary();
            _surface = new Surface(canvas1, _laosBorder);
            _osmRenderer = new OsmRender(_surface);
            _osmRenderer._delegateReport += Report;

            _placesRenderer = new PlacesRender(_surface);
            _ciaRender = new CIARender(_surface);
            _ciaRender._delegateReport += Report;
            _RenderOpenMapLibrary = new RenderOpenMapLibrary(_openMapLibrary, _surface);
            _RenderOpenMapLibrary._delegateReport += Report;
            _placesRenderer._delegateReport += Report;

            _osmRenderer._delegateToggleWay += RouteManager.ToggleWay;
            _surface._delegateNewViewPort += ReportViewPort;

            canvas1.MouseDown += canvas1_MouseDown;

           // string sz = @"c:\temp\Lingua-LO-Romanize-0.08.tar.gz";
           // ArchiveLoader.Decompress(sz);
        }

        void canvas1_MouseDown(object sender, MouseButtonEventArgs e)
        {
            _surface.ZoomIn10Pixel(e.GetPosition(canvas1));
            RedrawMap();
        }

        // http://geonames.nga.mil/ggmagaz/



        //http://www.evl.uic.edu/pape/data/WDB/
        private void Button1Click(object sender, RoutedEventArgs e)
        {

            //RDLINE.E00.GZ

            //string f = @"C:\laomapdata\RDLINE.E00.GZ";
            // Decompress(f);

            canvas1.Children.Clear();
            _ciaRender.DoPlotPoly(_segments2, _laosBorder, canvas1);
            _placesRenderer.DoPlot2(_places, canvas1);
        }

        private void ButtonLoadClick(object sender, RoutedEventArgs e)
        {
            canvas1.Children.Clear();
            _placesRenderer.DoPlot2(_places, canvas1);
            _ciaRender.DoPlotPoly(_segments2, _laosBorder, canvas1);
        }


        private void ButtonResetZoomClick(object sender, RoutedEventArgs e)
        {
            _surface.ZoomFullOut();
            RedrawMap();
        }

        private void ButtonOsmClick(object sender, RoutedEventArgs e)
        {
            Osm.Clear();
            OsmCache.FromCache();
            _osmRenderer.DoOsmPlot(canvas1);
        }

        private void ButtonCiaReadClick(object sender, RoutedEventArgs e)
        {
            PlacesLoader.Load(_places);
            ArchiveLoader.ReadBoundaries(_segments2, _laosBorder);
        }

        private void ButtonOsmInspectClick(object sender, RoutedEventArgs e)
        {
            Dictionary<string, string> highwayTypes = new Dictionary<string, string>();

            foreach (OsmWay n in Osm.Ways.Values)
            {
                foreach (string sz in n._tags.Keys)
                {
                    foreach (string sz1 in n._tags[sz])
                    {
                        if (sz == "highway")
                        {
                            if (!highwayTypes.ContainsKey(sz1))
                            {
                                highwayTypes.Add(sz1, "");
                            }
                        }
                        else
                        {
                            Debug.WriteLine("way key " + sz + " value " + sz1);
                        }
                    }
                }

                Debug.WriteLine("");

                foreach (OsmNode n1 in n.Nodes)
                {
                    foreach (string sz in n1._tags.Keys)
                    {
                        if (sz == "created_by")
                            continue;
                        Debug.WriteLine("    node key " + sz + " value " + n1._tags[sz]);
                    }
                }

            }

            foreach (var w in highwayTypes.Keys)
            {
                Debug.WriteLine("    ++++ highway type " + w);
            }
        }

        private void buttonZoomOut2_Click(object sender, RoutedEventArgs e)
        {
            _surface.ZoomOut(2);
            RedrawMap();
        }

        private void RedrawMap()
        {
            canvas1.Children.Clear();
            _RenderOpenMapLibrary.DoPlot(canvas1);
            _ciaRender.DoPlotPoly(_segments2, _laosBorder, canvas1);
            _osmRenderer.DoOsmPlot(canvas1);
            _placesRenderer.DoPlot2(_places, canvas1);

            if (_dlgCanvas != null)
            {
                _dlgCanvas.Children.Clear();
                _osmRenderer.DoOsmPlotPicker(_dlgCanvas, RouteManager.GetSelection);
            }

            if (_dlgCanvasMap != null)
            {
                _dlgCanvasMap.Children.Clear();
                _osmRenderer.DoOsmPlotPickerMap(_dlgCanvasMap);
            }
        }

        private void buttonUp_Click(object sender, RoutedEventArgs e)
        {
            _surface.Pan(0, -0.25);
            RedrawMap();
        }

        private void buttonDown_Click(object sender, RoutedEventArgs e)
        {
            _surface.Pan(0, 0.25);
            RedrawMap();
        }

        private void buttonLeft_Click(object sender, RoutedEventArgs e)
        {
            _surface.Pan(0.25, 0);
            RedrawMap();
        }

        private void buttonRight_Click(object sender, RoutedEventArgs e)
        {
            _surface.Pan(-0.25, 0);
            RedrawMap();
        }

        private void buttonRouteGen_Click(object sender, RoutedEventArgs e)
        {
            RouteManager.LoadCache();
            DlgRouteGenereator dlg = new DlgRouteGenereator();

            dlg.Owner = this;
            _dlgCanvas = dlg.canvas1;
            dlg.textBoxRouteName.Text = RouteManager.GetLoadedRouteName();
            dlg._closeDlg += CloseDlg;
            dlg._saveCache += RouteManager.SaveCache;
            dlg._clearCurrent += Clear;
            dlg._animateCurrent += RouteManager.AnimateCurrent;
            dlg._places = _places;
            dlg.Show();

            _dlgCanvas.Children.Clear();
            _osmRenderer.DoOsmPlotPicker(_dlgCanvas, RouteManager.GetSelection);
        }

        private void button2Map_Click(object sender, RoutedEventArgs e)
        {
            DlgMap dlg = new DlgMap();
            dlg.Owner = this;
            _dlgCanvasMap = dlg.canvas1;
            dlg.Show();
            _dlgCanvasMap.Children.Clear();
            _osmRenderer.DoOsmPlotPickerMap(_dlgCanvasMap);
        }

        public void CloseDlg()
        {
            _dlgCanvas = null;
        }

        private void Clear()
        {
            RouteManager.ClearCurrent();
            if (_dlgCanvas != null)
            {
                _dlgCanvas.Children.Clear();
                _osmRenderer.DoOsmPlotPicker(_dlgCanvas, RouteManager.GetSelection);
            }
        }

        void Report(string sz)
        {
            if (textBoxReport.Text.Length > 100000)
            {
                textBoxReport.Text = "";
            }
            textBoxReport.Text = sz + "\r\n" + textBoxReport.Text;
        }

        void ReportViewPort(string sz)
        {
            textBoxView.Text = sz;
        }

        private void buttonLoadML_Click(object sender, RoutedEventArgs e)
        {
            _openMapLibrary.LoadMapLib();
        }

        private void buttonCreateBin_Click(object sender, RoutedEventArgs e)
        {
            OsmBinWriter w = new OsmBinWriter(Osm.Ways, Osm.NamedNodes);
            w.WriteFile(@"f:\osm\osm.bin");
        }

        private void buttonLoadBin_Click(object sender, RoutedEventArgs e)
        {
            OsmBinLoader l = new OsmBinLoader(Osm.Ways, Osm.NamedNodes);
            l.ReadFile(@"f:\osm\osm.bin");
        }

        private void buttonCookieCutter_Click(object sender, RoutedEventArgs e)
        {
            //Run the border order, save the osm bin first! The laos norder ways must be ordered first!

            CookieCutter cutter = new CookieCutter(_surface);
            cutter.Cut();
            RedrawMap();
        }

        private void buttonOrderBorder_Click(object sender, RoutedEventArgs e)
        {
            CookieCutter cutter = new CookieCutter(_surface);

            // get the Laos national border from the CIA world map
            // It doesn't co-incide with the OSM data, but it is ordered correctly for a ploygon
            // error - probably not WGS84
            cutter.ReorderLaosBorderWays();

            LaosBorder laosBorder = new LaosBorder();
            Dictionary<string, MapSegment> normalSegments = new Dictionary<string, MapSegment>();
            ArchiveLoader.ReadBoundaries(normalSegments, laosBorder);
            laosBorder.SaveBorder(@"f:\osm\border.bin");
            laosBorder.LoadBorder(@"f:\osm\border.bin");
            cutter.ShowBorder(laosBorder._geoPolygon, canvas1);

            _osmRenderer.DoOsmPlotBorder(canvas1);
        }

        private void buttonTowns_Click(object sender, RoutedEventArgs e)
        {
            foreach (OsmNode n in Osm.NamedNodes)
            {
                if (n.IsPlace)
                {
                    string value;
                    if (n._tags.TryGetValue("name:en", out value))
                    {
                        Debug.WriteLine("" + value);
                    }
                }
            }
        }

        void FileBorderHelper(string filename)
        {
            CookieCutter cutter = new CookieCutter(_surface);

            // get the Laos national border from the CIA world map
            // It doesn't co-incide with the OSM data, but it is ordered correctly for a ploygon
            // error - probably not WGS84
            List<Point> Points = cutter.ReorderLaosBorderWays();

            if (File.Exists(filename))
            {
                File.Delete(filename);
            }

            FileStream fs = File.Create(filename);

            var unicode = new UnicodeEncoding();

            using (var bw = new BinaryWriter(fs, unicode))
            {
                bw.Write(Points.Count);

                foreach (var coord in Points)
                {
                    bw.Write(coord.Y);
                    bw.Write(coord.X);
                }
                bw.Flush();
                bw.Close();
            }
        }

        private void buttonCreateBorder_Click(object sender, RoutedEventArgs e)
        {
            FileBorderHelper(@"f:\osm\border.bin");
        }
    }

    internal class SortByTagIndex : IComparer<OsmWay>
    {
        public int Compare(OsmWay x, OsmWay y)
        {
            return x.GetBoarderIndexTag() - y.GetBoarderIndexTag();
        }
    }

    internal class SortByIndex : IComparer<WayVoter>
    {
        public int Compare(WayVoter x, WayVoter y)
        {
            return x._index - y._index;
        }
    }

    class WayVoter
    {
        public WayVoter(OsmWay osmWay)
        {
            _osmWay = osmWay;
        }

        public OsmWay _osmWay;
        public int _index = 0;
        public bool _reverseRender;
        public double _distance = double.PositiveInfinity;
    }
}
